﻿using System;
using System.Diagnostics.Contracts;
using System.Runtime.InteropServices;

namespace O1.Kernel
{
    [ContractVerification(true)]
    [StructLayout(LayoutKind.Explicit)]
    public struct Vertex : IEquatable<Vertex>
    {
        public const int Size = Sz.CLR.Int32 * 2;

        [FieldOffset(0)]
        public readonly int FirstEdgeId;

        [FieldOffset(Sz.CLR.Int32)]
        public readonly int FirstPropertyId;

        public Vertex(
            int firstEdgeId,
            int firstPropertyId)
            : this()
        {
            this.FirstEdgeId = firstEdgeId;
            this.FirstPropertyId = firstPropertyId;
        }

        public static bool operator ==(Vertex instance, Vertex other)
        {
            return instance.Equals(other);
        }

        public static bool operator !=(Vertex instance, Vertex other)
        {
            return !instance.Equals(other);
        }

        public bool Equals(Vertex other)
        {
            return
                this.FirstEdgeId == other.FirstEdgeId &&
                this.FirstPropertyId == other.FirstPropertyId;
        }

        public override bool Equals(object obj)
        {
            if (obj == null)
            {
                return false;
            }

            if (obj.GetType() != typeof(Vertex))
            {
                return false;
            }

            return this.Equals((Vertex)obj);
        }

        public override int GetHashCode()
        {
            return this.FirstEdgeId.GetHashCode() ^ this.FirstPropertyId.GetHashCode();
        }

        internal static unsafe Vertex Read(byte[] buffer, int offset)
        {
            Contract.Requires(buffer != null);
            Contract.Requires(0 <= offset);
            Contract.Requires(offset + Size < buffer.Length, ExceptionText.ValueBufferTooSmall);

            fixed (byte* p = &buffer[offset])
            {
                return *(Vertex*)p;
            }
        }

        internal unsafe void Write(byte[] buffer, int offset)
        {
            Contract.Requires(buffer != null);
            Contract.Requires(0 <= offset);
            Contract.Requires(offset + Size < buffer.Length, ExceptionText.ValueBufferTooSmall);

            fixed (byte* p = &buffer[offset])
            {
                *(Vertex*)p = this;
            }
        }
    }
}
